package com.wigem.approve.service;

import cn.dev33.satoken.stp.StpUtil;
import com.wigem.approve.entity.*;
import com.wigem.approve.mapper.DaqEstateMapper;
import com.wigem.approve.mapper.DaqPolicyMapper;
import com.wigem.approve.utils.EcoExcelUtils;
import com.wigem.approve.vo.DaqEnterpriseVo;
import com.wigem.approve.vo.DaqEstateVo;
import com.wigem.approve.vo.DaqPolicyVo;
import com.wigem.framework.common.pojo.PageResult;
import com.wigem.framework.common.util.OkHttpUtils;
import com.wigem.framework.common.util.common.FileUtils;
import com.wigem.framework.common.util.common.StringUtils;
import com.wigem.framework.sa.token.core.UserInfo;
import com.wigem.framework.sa.token.core.util.SaTokenUtils;
import com.wigem.framework.word.core.util.WordTemplate;
import com.wigem.system.entity.SystemAnnexEntity;
import com.wigem.system.mapper.SystemAnnexMapper;
import com.wigem.system.service.SystemAnnexService;
import org.apache.xmlbeans.impl.jam.provider.ResourcePath;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
public class ExportServiceImpl implements ExportService {

    @Resource
    private DaqEstateService daqEstateService;
    @Resource
    private DaqEstateMapper daqEstateMapper;

    @Resource
    private DaqEnterpriseService daqEnterpriseService;

    @Resource
    private DaqPolicyService daqPolicyService;

    @Resource
    private SystemAnnexService systemAnnexService;

    @Resource
    private SystemAnnexMapper systemAnnexMapper;

    @Autowired
    private Environment environment;

    @Override
    public void exportExcel(HttpServletResponse response, ElementPlusTableModel tableModel) throws IOException {
        String dataStr = getTableData(tableModel);
        new EcoExcelUtils(tableModel, dataStr).doExport(response);
    }

    private String getTableData(ElementPlusTableModel elementPlusTableModel) {
        OkHttpUtils builder = OkHttpUtils.builder();
        LinkedHashMap<String, String> queryMap = elementPlusTableModel.getQueryJson();
        Integer pageNo = 1;
        Integer pageSize = 50000;
        queryMap.put("pageNo", pageNo.toString());
        queryMap.put("pageSize", pageSize.toString());
        return builder.addHeader(StpUtil.getTokenName(), StpUtil.getTokenValue())
                .url("http://localhost:" + environment.getProperty("server.port") + "/api" + elementPlusTableModel.getUrl())
                .addParams(queryMap)
                .get()
                .sync();
    }

    @Override
    public void exportEstate(HttpServletResponse response, DaqPolicyVo daqPolicyVo) throws Exception {
        try {
            InputStream resourceAsStream = ResourcePath.class.getResourceAsStream("/wordTemplate/estate.docx");
            WordTemplate wordTemplate = new WordTemplate(resourceAsStream);
            DaqEstateEntity daqEstateEntity = daqEstateService.getEntityByPolicyId(daqPolicyVo.getId());
            wordTemplate.addContexts(daqEstateEntity);
            wordTemplate.download(response, "商务楼宇信息登记表.docx");
        } catch (Exception exception) {
            System.out.println(exception);
        }
    }

    private static final String FILE_TYPE = ".zip";

    private void copyFileForFolderId(List<String> folderIdList, String filePath) throws Exception {
        List<SystemAnnexEntity> annexList = systemAnnexService.getBatchListByFolderId(folderIdList);
        if (annexList != null && annexList.size() > 0) {
            annexList.stream().forEach(annex -> {
                File sourceFile = new File(annex.getFilePath());
                File destinationFile = new File(filePath + "/" + annex.getFileName());
                try {
                    this.copyFile(sourceFile, destinationFile);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }

    @Override
    public void exportPolicy(HttpServletResponse response, DaqPolicyVo daqPolicyVo) throws Exception {
        String filePath = "D:\\data/downLoad";
        String outPath = "D:\\data/";
        /*String filePath = "/data/downLoad";
        String outPath = "/data/";*/
        String outFileName = "";
        //创建临时文件夹
        this.createFile(filePath);
        //将所有要下载的文件放到临时文件夹中
        //根据政策id获取estateId及附件id
        DaqEstateEntity daqEstateEntity = daqEstateService.getEntityByPolicyId(daqPolicyVo.getId());
        InputStream resourceAsStream = ResourcePath.class.getResourceAsStream("/wordTemplate/estate.docx");

        outFileName = daqEstateEntity.getEstateName() + FILE_TYPE;
        outPath += daqEstateEntity.getEstateName() + FILE_TYPE;

        try {
            WordTemplate wordTemplate = new WordTemplate(resourceAsStream);
            wordTemplate.addContexts(daqEstateEntity);
            wordTemplate.build().save(filePath + "/商务楼宇信息登记表.docx");
        } catch (Exception e) {
            e.printStackTrace();
        }

        List<String> folderIdList = new ArrayList<>();
        if (!StringUtils.isEmpty(daqEstateEntity.getBuildingCertificate())) {
            //楼宇产权证明材料复印件
            folderIdList.add(daqEstateEntity.getBuildingCertificate());
        }
        if (!StringUtils.isEmpty(daqEstateEntity.getBusinessLicense())) {
            //营业执照
            folderIdList.add(daqEstateEntity.getBusinessLicense());
        }
        DaqPolicyEntity daqPolicyEntity = daqPolicyService.getEntity(daqPolicyVo.getId());
        if (!StringUtils.isEmpty(daqPolicyEntity.getCommitmenLetter())) {
            //承诺书
            folderIdList.add(daqPolicyEntity.getCommitmenLetter());
        }
        if (folderIdList.size() > 0) {
            this.copyFileForFolderId(folderIdList, filePath);
        }
        //楼宇信息表
        try {
            String tableName = "存量商务楼宇信息统计表";
            ElementPlusTableModel tableModel = new ElementPlusTableModel();
            tableModel.setUrl("/approve/daqEstate/query/page");
            LinkedHashMap<String, String> queryJson = new LinkedHashMap<>();
            queryJson.put("policyId", daqPolicyVo.getId());
            queryJson.put("removeMark", "0");
            tableModel.setQueryJson(queryJson);
            tableModel.setCols(getEstateCols());
            tableModel.setTableName(tableName);
            tableModel.setTitle(tableName);
            List<TableRemarkModel> tableRemarks = new ArrayList<>();
            tableModel.setTableRemarks(tableRemarks);
            String dataStr = getTableData(tableModel);
            new EcoExcelUtils(tableModel, dataStr).downLoad(filePath + "/" + tableName + ".xlsx");
        } catch (Exception e) {
            e.printStackTrace();
        }
        //企业信息表
        try {
            String tableName = "存量商务楼宇入驻企业统计表";
            ElementPlusTableModel tableModel = new ElementPlusTableModel();
            tableModel.setUrl("/approve/enterprise/export/query");
            LinkedHashMap<String, String> queryJson = new LinkedHashMap<>();
            queryJson.put("policyId", daqPolicyVo.getId());
            queryJson.put("removeMark", "0");
            tableModel.setQueryJson(queryJson);
            tableModel.setCols(getEnterpriseCols());
            tableModel.setTableName(tableName);
            tableModel.setTitle(tableName);
            List<TableRemarkModel> tableRemarks = new ArrayList<>();
            tableModel.setTableRemarks(tableRemarks);
            String dataStr = getTableData(tableModel);
            new EcoExcelUtils(tableModel, dataStr).downLoad(filePath + "/" + tableName + ".xlsx");
        } catch (Exception e) {
            e.printStackTrace();
        }
        //将临时文件压缩zip
        zipFolder(filePath, outPath);
        //下载zip文件
        FileUtils.downLoad(response, outPath, outFileName);
    }

    @Override
    public void exportAll(HttpServletResponse response, DaqPolicyVo daqPolicyVo) throws Exception {
        UserInfo userInfo = SaTokenUtils.getLoginUserInfo();
        DaqEstateVo daqEstateVo = new DaqEstateVo();
        //todo 这里可以加判断如果没有报告期id则获取最新报告期导出
        daqEstateVo.setReportId(daqPolicyVo.getReportId());
        daqEstateVo.setRemoveMark("0");
        List<DaqEstateEntity> daqEstateEntityList = daqEstateMapper.getList(daqEstateVo);
        //todo 判断数据不为空则继续执行导出流程
        //获取到当前报告期的所有楼宇之后循环导出附件
        String filePath = "D:\\data/downLoad";
        String outPath = "D:\\data/政策申报文件.zip";
        //获取word模版文件地址
        List<String> annexFolderIdList = new ArrayList<>();
        daqEstateEntityList.stream().forEach(estateEntity -> {
            if (!StringUtils.isEmpty(estateEntity.getBuildingCertificate())) {
                annexFolderIdList.add(estateEntity.getBuildingCertificate());
            }
            if (!StringUtils.isEmpty(estateEntity.getBusinessLicense())) {
                annexFolderIdList.add(estateEntity.getBusinessLicense());
            }
        });
        //获取所有的附件
        List<SystemAnnexEntity> annexList = systemAnnexService.getBatchListByFolderId(annexFolderIdList);
        for (DaqEstateEntity daqEstateEntity : daqEstateEntityList) {
            //循环导出，包含每个楼宇的三个附件和两个组合的楼宇信息表
            //定义临时导出附件的存储地址
            String estateItemFileName = daqEstateEntity.getEstateName().replaceAll("\\s", "");
            String estateItemFilePath = filePath + "/" + estateItemFileName;
            try {
                InputStream resourceAsStream = ResourcePath.class.getResourceAsStream("/wordTemplate/estate.docx");
                this.createFile(estateItemFilePath);
                //生成estateWord
                WordTemplate wordTemplate = new WordTemplate(resourceAsStream);
                wordTemplate.addContexts(daqEstateEntity);
                wordTemplate.build().save(estateItemFilePath + "/商务楼宇信息登记表.docx");
            } catch (Exception e) {
                e.printStackTrace();
            }
            List<SystemAnnexEntity> estateAnnexList = annexList.stream().filter(annex -> {
                return annex.getFolderId().equals(daqEstateEntity.getBuildingCertificate()) || annex.getFolderId().equals(daqEstateEntity.getBusinessLicense());
            }).collect(Collectors.toList());
            for (SystemAnnexEntity estateAnnex : estateAnnexList) {
                if (estateAnnex != null) {
                    File sourceFile = new File(estateAnnex.getFilePath());
                    File destinationFile = new File(estateItemFilePath + "/" + estateAnnex.getFileName());
                    try {
                        this.copyFile(sourceFile, destinationFile);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
            try {
                //拼接当前楼的两个附件id信息用作查询条件、一次将两个附件地址全部查询出来
                List<String> idList = new ArrayList<>();
                idList.add(daqEstateEntity.getBusinessLicense());
                idList.add(daqEstateEntity.getBuildingCertificate());
                //查到之后根据文件地址进行copy操作
                copyFileForFolderId(idList, estateItemFilePath);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

        //生成楼宇信息表
        try {
            String tableName = "存量商务楼宇信息统计表";
            ElementPlusTableModel tableModel = new ElementPlusTableModel();
            tableModel.setUrl("/approve/daqEstate/query");
            LinkedHashMap<String, String> queryJson = new LinkedHashMap<>();
            queryJson.put("reportId", daqPolicyVo.getReportId());
            queryJson.put("removeMark", "0");
            tableModel.setQueryJson(queryJson);
            tableModel.setCols(getEstateCols());
            tableModel.setTableName(tableName);
            tableModel.setTitle(tableName);
            List<TableRemarkModel> tableRemarks = new ArrayList<>();
            tableModel.setTableRemarks(tableRemarks);
            String dataStr = getTableData(tableModel);
            new EcoExcelUtils(tableModel, dataStr).downLoad(filePath + "/" + tableName + ".xlsx");
        } catch (Exception e) {
            e.printStackTrace();
        }
        //企业信息表
        try {
            String tableName = "存量商务楼宇入驻企业统计表";
            ElementPlusTableModel tableModel = new ElementPlusTableModel();
            tableModel.setUrl("/approve/enterprise/query");
            LinkedHashMap<String, String> queryJson = new LinkedHashMap<>();
            queryJson.put("reportId", daqPolicyVo.getReportId());
            queryJson.put("removeMark", "0");
            tableModel.setQueryJson(queryJson);
            tableModel.setCols(getEnterpriseCols());
            tableModel.setTableName(tableName);
            tableModel.setTitle(tableName);
            List<TableRemarkModel> tableRemarks = new ArrayList<>();
            tableModel.setTableRemarks(tableRemarks);
            String dataStr = getTableData(tableModel);
            new EcoExcelUtils(tableModel, dataStr).downLoad(filePath + "/" + tableName + ".xlsx");
        } catch (Exception e) {
            e.printStackTrace();
        }
        //将临时文件压缩zip
        zipFolder(filePath, outPath);
        //下载zip文件
        FileUtils.downLoad(response, outPath, "政策申报文件.zip");
    }

    private List<ElementPlusTableColumnModel> getEstateCols() {
        List<ElementPlusTableColumnModel> cols = new ArrayList<>();
        ElementPlusTableColumnModel col1 = new ElementPlusTableColumnModel();
        col1.setProp("estateName");
        col1.setLabel("楼宇名称");
        cols.add(col1);
        ElementPlusTableColumnModel col2 = new ElementPlusTableColumnModel();
        col2.setProp("estateAddr");
        col2.setLabel("楼宇详细地址");
        cols.add(col2);
        ElementPlusTableColumnModel col3 = new ElementPlusTableColumnModel();
        col3.setProp("propertyUnit");
        col3.setLabel("产权单位");
        cols.add(col3);
        ElementPlusTableColumnModel col4 = new ElementPlusTableColumnModel();
        col4.setProp("propertyUnitSocialCreditCode");
        col4.setLabel("产权单位统一社会信用代码");
        cols.add(col4);
        ElementPlusTableColumnModel col5 = new ElementPlusTableColumnModel();
        col5.setProp("operatingUnit");
        col5.setLabel("运营或招商管理单位");
        cols.add(col5);
        ElementPlusTableColumnModel col6 = new ElementPlusTableColumnModel();
        col6.setProp("operatingUnitSocialCreditCode");
        col6.setLabel("运营或招商管理单位统一社会信用代码");
        cols.add(col6);
        ElementPlusTableColumnModel col7 = new ElementPlusTableColumnModel();
        col7.setProp("operatingUnitLegalRepresentative");
        col7.setLabel("运营或招商管理单位法定代表人");
        cols.add(col7);
        ElementPlusTableColumnModel col8 = new ElementPlusTableColumnModel();
        col8.setProp("operatingUnitLinkmanName");
        col8.setLabel("运营或招商管理单位联系人姓名");
        cols.add(col8);
        ElementPlusTableColumnModel col9 = new ElementPlusTableColumnModel();
        col9.setProp("operatingUnitLinkmanJob");
        col9.setLabel("运营或招商管理单位联系人职务");
        cols.add(col9);
        ElementPlusTableColumnModel col10 = new ElementPlusTableColumnModel();
        col10.setProp("operatingUnitLinkmanPhone");
        col10.setLabel("联系人电话");
        cols.add(col10);
        ElementPlusTableColumnModel col11 = new ElementPlusTableColumnModel();
        col11.setProp("totalArea");
        col11.setLabel("总面积");
        cols.add(col11);
        ElementPlusTableColumnModel col12 = new ElementPlusTableColumnModel();
        col12.setProp("officeArea");
        col12.setLabel("写字楼面积");
        cols.add(col12);
        ElementPlusTableColumnModel col13 = new ElementPlusTableColumnModel();
        col13.setProp("hotelArea");
        col13.setLabel("酒店面积");
        cols.add(col13);
        ElementPlusTableColumnModel col14 = new ElementPlusTableColumnModel();
        col14.setProp("residentialArea");
        col14.setLabel("住宅面积");
        cols.add(col14);
        ElementPlusTableColumnModel col15 = new ElementPlusTableColumnModel();
        col15.setProp("commercialArea");
        col15.setLabel("商业面积");
        cols.add(col15);
        ElementPlusTableColumnModel col16 = new ElementPlusTableColumnModel();
        col16.setProp("otherArea");
        col16.setLabel("其它面积");
        cols.add(col16);
        ElementPlusTableColumnModel col17 = new ElementPlusTableColumnModel();
        col17.setProp("ownershipUnitArea");
        col17.setLabel("产权单位自持面积");
        cols.add(col17);
        ElementPlusTableColumnModel col18 = new ElementPlusTableColumnModel();
        col18.setProp("officeLeasedArea");
        col18.setLabel("写字楼对外出租面积");
        cols.add(col18);
        ElementPlusTableColumnModel col19 = new ElementPlusTableColumnModel();
        col19.setProp("officeLeasedArea");
        col19.setLabel("商业部分平均租金");
        cols.add(col19);
        ElementPlusTableColumnModel col20 = new ElementPlusTableColumnModel();
        col20.setProp("officeAverageRent");
        col20.setLabel("商业部分平均租金");
        cols.add(col20);
        return cols;
    }

    private List<ElementPlusTableColumnModel> getEnterpriseCols() {
        List<ElementPlusTableColumnModel> cols = new ArrayList<>();
        ElementPlusTableColumnModel col2 = new ElementPlusTableColumnModel();
        col2.setProp("orgName");
        col2.setLabel("企业名称");
        cols.add(col2);
        ElementPlusTableColumnModel col1 = new ElementPlusTableColumnModel();
        col1.setProp("socialCreditCode");
        col1.setLabel("社会信用代码");
        cols.add(col1);
        ElementPlusTableColumnModel col3 = new ElementPlusTableColumnModel();
        col3.setProp("regTime");
        col3.setLabel("成立日期");
        cols.add(col3);
        ElementPlusTableColumnModel col4 = new ElementPlusTableColumnModel();
        col4.setProp("orgRegAddr");
        col4.setLabel("工商注册地址");
        cols.add(col4);
        ElementPlusTableColumnModel col5 = new ElementPlusTableColumnModel();
        col5.setProp("useProperty");
        col5.setLabel("办公用房性质");
        cols.add(col5);
        ElementPlusTableColumnModel col6 = new ElementPlusTableColumnModel();
        col6.setProp("officeArea");
        col6.setLabel("租用/自用办公面积（㎡）");
        cols.add(col6);
        ElementPlusTableColumnModel col7 = new ElementPlusTableColumnModel();
        col7.setProp("checkInTime");
        col7.setLabel("入驻时间");
        cols.add(col7);
        ElementPlusTableColumnModel col8 = new ElementPlusTableColumnModel();
        col8.setProp("rentTime");
        col8.setLabel("房屋租期（*年*月-*年*月）");
        cols.add(col8);
        return cols;
    }

    /**
     * 压缩文件夹
     *
     * @param folderPath  文件夹路径
     * @param zipFilePath 压缩文件路径（输出路径）
     * @throws IOException
     */
    /*private static void zipFolder(String folderPath, String zipFilePath) throws IOException {
        File folder = new File(folderPath);
        FileOutputStream fos = new FileOutputStream(zipFilePath);
        ZipOutputStream zos = new ZipOutputStream(fos);

        File[] files = folder.listFiles();
        byte[] buffer = new byte[1024];
        int length;

        for (File file : files) {
            FileInputStream fis = new FileInputStream(file);
            ZipEntry zipEntry = new ZipEntry(file.getName());
            zos.putNextEntry(zipEntry);

            while ((length = fis.read(buffer)) > 0) {
                zos.write(buffer, 0, length);
            }

            zos.closeEntry();
            fis.close();
        }

        zos.close();
        fos.close();
    }*/

    /**
     * 删除文件夹
     *
     * @param dir 文件夹
     * @return 是否删除成功
     */
    private static boolean deleteDirectory(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (String aChildren : children) {
                boolean success = deleteDirectory(new File(dir, aChildren));
                if (!success) {
                    return false;
                }
            }
        }

        // 目录现在为空，可以删除
        return dir.delete();
    }

    private Boolean createFile(String folderPath) {
        //String folderPath = "/path/to/new/folder";
        File folder = new File(folderPath);
        // 判断文件夹是否存在，存在则删除后重新创建
        boolean result = false;
        if (folder.exists()) {
            deleteDirectory(folder);
        }
        result = folder.mkdirs(); // 创建包括所有必需的父目录
        return result;
    }

    private static void copyFile(File sourceFile, File destinationFile) throws IOException {
        if (!sourceFile.exists()) {
            throw new FileNotFoundException("源文件不存在: " + sourceFile);
        }

        if (!destinationFile.getParentFile().exists()) {
            if (!destinationFile.getParentFile().mkdirs()) {
                throw new IOException("无法创建目标目录: " + destinationFile.getParent());
            }
        }

        FileInputStream fis = new FileInputStream(sourceFile);
        FileOutputStream fos = new FileOutputStream(destinationFile);

        byte[] buffer = new byte[1024];
        int length;
        while ((length = fis.read(buffer)) > 0) {
            fos.write(buffer, 0, length);
        }

        fis.close();
        fos.close();
    }

    public static void zipFolder(String folderPath, String zipFilePath) throws IOException {
        File folder = new File(folderPath);
        if (!folder.exists() || !folder.isDirectory()) {
            throw new IOException("Folder does not exist or is not a directory.");
        }

        try (FileOutputStream fos = new FileOutputStream(zipFilePath);
             ZipOutputStream zos = new ZipOutputStream(fos)) {

            zipFolderRecursively(folder, folderPath, zos);
        }
    }

    private static void zipFolderRecursively(File folder, String basePath, ZipOutputStream zos) throws IOException {
        File[] files = folder.listFiles();
        if (files == null) {
            return; // Empty directory or I/O error occurred
        }

        for (File file : files) {
            String filePath = file.getPath();
            if (file.isDirectory()) {
                // For directories, we create a new directory entry in the zip file
                zipFolderRecursively(file, basePath, zos);
            } else {
                // For files, we add the file to the zip output stream
                addToZip(file, filePath.substring(basePath.length() + 1), zos);
            }
        }
    }

    private static void addToZip(File file, String zipFilePath, ZipOutputStream zos) throws IOException {
        try (FileInputStream fis = new FileInputStream(file)) {
            ZipEntry zipEntry = new ZipEntry(zipFilePath);
            zos.putNextEntry(zipEntry);

            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) > 0) {
                zos.write(buffer, 0, length);
            }

            zos.closeEntry();
        }
    }

}
